/************************************************************************
Copyright 2003, 2004, 2005, 2006, 2007, 2008 Grid Technology Research Center,
National Institute of Advanced Industrial Science and Technology.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************/

package jp.aist.gtrc.plus.command.util;

import java.util.Calendar;

import jp.aist.gtrc.plus.reserve.ReserveException;
import jp.aist.gtrc.plus.scheduler.node.ResourceOption;
import jp.aist.gtrc.plus.scheduler.status.ArchType;
import jp.aist.gtrc.plus.scheduler.status.OSType;
import jp.aist.gtrc.plus.scheduler.util.TextUtil;

public class PlusReserveOptions extends PlusCommandOptions {

	private static final String OPT_REQ_MEM = "-mem";
	private static final String OPT_REQ_CPUNUM = "-ncpu";
	private static final String OPT_REQ_ARCH = "-arch";
	private static final String OPT_REQ_OS = "-os";
	private static final String OPT_REQ_RSC = "-l";
	private static final String OPT_MAKE_PREPOSTQ = "-p";
	private static final String OPT_SLOT_NUM = "-sn";
	private static final String OPT_SGE_QNAME = "-sgeq";
	private static final String OPT_SHOW_SIMPLE = "-x";

	private static final int NO_CPUNUM = -1;
	private static final long NO_MEM = -1;


	public PlusReserveOptions(String appName) {

		super(appName);

		StringBuffer sb = new StringBuffer();
		for (OSType os : OSType.values()) {
			sb.append(os.name());
			sb.append(' ');
		}
		String osNames = sb.toString().trim();

		sb = new StringBuffer();
		for (ArchType arch : ArchType.values()) {
			sb.append(arch.name());
			sb.append(' ');
		}
		String archNames = sb.toString().trim();

		addOption(transaction());
		addOption(startTime(true));
		addOption(endTime(false));
		addOption(duration());
		addOption(nodeNum(true));
		addOption(users(true));

		addOption(OPT_REQ_MEM, "memSize", "requested memory size on reserved node, size[kKmMgGtT]", null);
		addOption(OPT_REQ_CPUNUM, "cpuNum", "requested CPU num on reserved node", null);
		addOption(OPT_REQ_ARCH, "arch", "requested CPU architecture (" + archNames + ")", null);
		addOption(OPT_REQ_OS, "os", "requested OS (" + osNames + ")", null);
		addOption(OPT_REQ_RSC, "rsc",
				"requested resource, almost same as qsub -l notaion (attr1[=value1][,...])", null);
		addOption(OPT_MAKE_PREPOSTQ, "make R??pre, R??post queues also, SGE only");
		addOption(OPT_SLOT_NUM, "slotNum", "number of slot of SGE reserve queue", null);
		addOption(OPT_SGE_QNAME, "qName", "restrict reserve nodes to nodes on the SGE queue", null);
		addOption(OPT_SHOW_SIMPLE, "show reservation id only, if succeeded");

	}

	public boolean isTransaction() {

		return super.isTransaction();

	}

	public Calendar getStartTime() throws ReserveException {

		return super.getStartTime();

	}

	public Calendar getEndTime() throws ReserveException {

		return super.getEndTime();

	}

	public int getDuration() throws ReserveException {

		return super.getDuration();

	}

	public int getNodeNum() throws ReserveException {

		return super.getNodeNum();

	}

	public String[] getUsers() {

		return super.getUsers();

	}

	public boolean isShowSimple() {

		return isOptionSet(OPT_SHOW_SIMPLE);

	}

	public boolean isMakePrePostQueue() {

		return isOptionSet(OPT_MAKE_PREPOSTQ);

	}

	private long getMemorySize() throws ReserveException {

		String n = getOptionValue(OPT_REQ_MEM);
		if (TextUtil.isValid(n)) {
			try {
				return (long)TextUtil.calcSize(n);
			} catch (NumberFormatException e) {
				throw new ReserveException("invalid memory size: " + n);
			}
		} else {
			return NO_MEM;
		}

	}

	private int getCPUNum() throws ReserveException {

		String n = getOptionValue(OPT_REQ_CPUNUM);
		if (TextUtil.isValid(n)) {
			try {
				int num = Integer.parseInt(n);
				if (num <= 0) {
					throw new ReserveException("CPU num must be positive");
				}
				return num;
			} catch (NumberFormatException e) {
				throw new ReserveException("invalid CPU num: " + n);
			}
		} else {
			return NO_CPUNUM;
		}

	}

	private ArchType getArchType() throws ReserveException {

		String n = getOptionValue(OPT_REQ_ARCH);
		if (TextUtil.isEmpty(n)) {
			return null;
		} else {
			ArchType arch = ArchType.valueOf(n);
			if (arch != null) {
				return arch;
			} else {
				throw new ReserveException("Invalid arch type : " + n);
			}
		}

	}

	private OSType getOSType() throws ReserveException {

		String n = getOptionValue(OPT_REQ_OS);
		if (TextUtil.isEmpty(n)) {
			return null;
		} else {
			OSType os = OSType.getOS(n);
			if (os != null) {
				return os;
			} else {
				throw new ReserveException("Invalid OS type : " + n);
			}
		}

	}

	private String[] getRequestedResources() {

		String r = getOptionValue(OPT_REQ_RSC);
		if (TextUtil.isValid(r)) {
			return r.split(",");
		} else {
			return new String[]{};
		}

	}

	private int getSlotNum() throws ReserveException {

		String n = getOptionValue(OPT_SLOT_NUM);
		if (TextUtil.isValid(n)) {
			try {
				int num = Integer.parseInt(n);
				if (num <= 0) {
					throw new ReserveException("slot num must be positive");
				}
				return num;
			} catch (NumberFormatException e) {
				throw new ReserveException("invalid slot num: " + n);
			}
		} else {
			return 0;
		}

	}

	private String getSGEQueueName() {

		return TextUtil.toNonNull(getOptionValue(OPT_SGE_QNAME));

	}

	public ResourceOption getResourceOption() throws ReserveException {

		ResourceOption reqOpts = new ResourceOption();
		if (isMakePrePostQueue() == true) {
			reqOpts.setMakePrePostQueue(true);
		}
		long size = getMemorySize();
		if (size != PlusReserveOptions.NO_MEM) {
			reqOpts.setNodePhysicalMemory(size);
		}
		int num = getCPUNum();
		if (num != PlusReserveOptions.NO_CPUNUM) {
			reqOpts.setNodeCPUNum(num);
		}
		reqOpts.setArchType(getArchType());
		reqOpts.setOSType(getOSType());
		int slotnum = getSlotNum();
		if (slotnum > 0) {
			reqOpts.setSlotNum(slotnum);
		}
		reqOpts.setSGEQueueName(getSGEQueueName());
		reqOpts.addResourceOptions(getRequestedResources());

		return reqOpts;

	}

}
